Algorithm
Back Tracking/Binary search
Back Tracking/Binary search 문제 풀기
모든 경우의 수를 따져야 할 때가 있다.
하지만 무식하게 모든 경우를 따져서 문제가 풀릴거면 문제가 왜있겠는가?
좀더 똑똑하게 모든 경우를 따져보자
BackTracking
BackTracking은 기본적으로 DFS를 하여 모든 분기를 따져보는 것이다. 중요한점은 두가지이다.
방법
- 분기가 나누어질때 문제 조건에 따라 가지치기를 한다.
- 뒤로 돌아갈때 바꾼 변수 등을 원래대로 되돌린다.
시간복잡도
BackTracking의 시간복잡도는 최악의 경우 $O(b^N)$이다.
b는 각 단계에서 분기하는 경우의 수, N은 문제의 크기이다.
(N-Queen 문제의 경우, queen을 두기/안두기 → b = 2, 체스판의 크기 nn → N = nn)
깨달음
- 시간 복잡도가 크므로, 가지치기를 최대한 해야한다.
- 또는 문제를 나누는 것도 방법이다. N이 커질수록 걸리는 시간이 기하급수적으로 증가하므로, 가능하다면 O(b^(N/2) + b^(N/2)) 따위로 줄일수 있다면 최고다. (N-Bishop 문제의 경우, 체스판을 흑/백으로 나누어 문제의 크기가 절반인 두 문제로 쪼갤수 있다.)
N개의 후보군 중 찾아야 하는 요소를 log(N)의 시간복잡도로 찾는다.
Binary Search
방법
- 상한과 하한을 지정하고, 상한과 하한이 맞닿을 때까지 반복을 수행한다.
- 루프 내에서는,
- 상한과 하한의 중앙값을 계산한다.
- 목표치를 문제에 맞게 계산한다.
- 상한과 하한을 갱신한다.
- 중앙값이 목표치보다 클 경우, 상한을 중앙값으로 설정한다.
- 중앙값이 목표치보다 작을 경우, 하한을 중앙값으로 설정한다.
- 중앙값이 목표치와 같을 경우, 루프를 종료한다.
주의점
- 상한과 하한의 초기값을 명확하게 지정해야한다, 더 좁은 범위를 지정해서는 안된다. but, 상한 두배 → 루프 1회 추가이므로 더 넓은 범위는 거의 상관없다.
- 루프를 도는 횟수가 log(N)이므로, 루프 안에서 어떤 계산을 할지 고려해야 한다. → 요소를 다 탐색하면 Nlog(N)의 시간 복잡도를 가진다.
- 문제의 조건에 맞게 상한과 하한을 갱신하여야 한다. → 목표치와 같다고 루프를 종료해서는 안될 때도 있다.